package dgbi;

import java.util.ArrayList;

public class BiGrafo {
    public ArrayList<Node> v1;
    public ArrayList<Node> v2;
    public ArrayList<Node> iv1;
    public ArrayList<Node> iv2;
    public ArrayList<int[]> iEjes;
//    public Integer[] posV1;
//    public Integer[] posV2;
    public int cruces;
    public boolean actualizado;
    public int cantOpertaciones;
    public int cantElementosOriginalV1;
    public int cantElementosOriginalV2;
    public int cantElementosOriginaliV1;
    public int cantElementosOriginaliV2;
    public int cantEjesFijo;
    public int cantEjesParticionAAgregar;

    //Constructor
    public BiGrafo(){
    	v1 = new ArrayList<Node>();
    	v2 = new ArrayList<Node>();
    	
    	iv1 = new ArrayList<Node>();
    	iv2 = new ArrayList<Node>();
    	iEjes = new ArrayList<int[]>();
    	
    }
    
    public void insertarEnV1(Node n,int pos){
        n.pos = pos;
        v1.add(pos,n);
        for(int i = pos+1; i< v1.size();i++){
            v1.get(i).pos++;                        //incremento en 1
        }
    }

    public void insertarEnV2(Node n,int pos){
        n.pos = pos;
        v2.add(pos,n);
        for(int i = pos+1; i< v2.size();i++){
            v2.get(i).pos++;                        //incremento en 1
        }
    }
    
    public void removerEnV1(int pos){
        
        v1.remove(pos);
        for(int i = pos; i< v1.size();i++){
            v1.get(i).pos--;                        //incremento en 1
        }
    }

    public void removerEnV2(int pos){
        
        v2.remove(pos);
        for(int i = pos; i< v2.size();i++){
            v2.get(i).pos--;                        //incremento en 1
        }
    }
    
    public void swapEnV1(int posIni,int posFin){  // hace swap solo en posiciones consecutivas, requiere |posIni-PosFin| = 1
        Node n = v1.get(posIni);
        n.pos = posFin;

  //      if(posIni<posFin){
                  
                v1.get(posFin).pos = posIni;
                v1.set(posIni, v1.get(posFin));
                v1.set(posFin, n);
//                v1.remove(posIni);
//                v1.add(posFin, n);
                return;
  /*          }
        else{
                v1.get(posFin).pos = posIni;
                v1.remove(posIni);
                v1.add(posFin, n);
                return;
            }
   * */
    }
    
        public void swapEnV2(int posIni,int posFin){  // hace swap solo en posiciones consecutivas, requiere |posIni-PosFin| = 1
        Node n = v2.get(posIni);
        n.pos = posFin;

 //       if(posIni<posFin){
                  
                v2.get(posFin).pos = posIni;
                
                v2.set(posIni, v2.get(posFin));
                v2.set(posFin, n);
                
  //              v2.remove(posIni);
  //              v2.add(posFin, n);
                return;
/*            }
        else{
                v2.get(posFin).pos = posIni;
                v2.remove(posIni);
                v2.add(posFin, n);
                return;
            }
 * */
    }
    
    
    public void moverEnV1(int posIni, int posFin){ //No es igual a swap, muevo 1 nodo de una posicion a otra;
       
        if(posIni==posFin) return;
        if(posIni == posFin-1){
            swapEnV1(posIni, posFin);
            return;
        }
        if(posFin== posIni-1){
            swapEnV1(posFin, posIni);
            return;
        }
        
        
        Node n = v1.get(posIni);
        n.pos = posFin;
        
        if(posIni<posFin){
            for(int i = posIni+1;i<=posFin;i++)
                v1.get(i).pos--;
            v1.remove(posIni);
            v1.add(posFin, n);                        // el -1 es porque lo elimine antes
        }
        else{
            for(int i = posFin;i<posIni;i++)
                v1.get(i).pos++;
            v1.remove(posIni);
            v1.add(posFin, n);
        }
 
    }    

    public void moverEnV2(int posIni, int posFin){ //No es igual a swap, muevo 1 nodo de una posicion a otra; 
        if(posIni==posFin) return;
        if(posIni == posFin-1){
            swapEnV2(posIni, posFin);
            return;
        }
        if(posFin== posIni-1){
            swapEnV2(posFin, posIni);
            return;
        }
        
        Node n = v2.get(posIni);
        n.pos = posFin;

        if(posIni<posFin){
            for(int i = posIni+1;i<=posFin;i++)
                v2.get(i).pos--;
            v2.remove(posIni);
            v2.add(posFin, n);                        // el -1 es porque lo elimine antes
        }
        else{
            for(int i = posFin;i<posIni;i++)
                v2.get(i).pos++;
            v2.remove(posIni);
            v2.add(posFin, n);
        }
   
    }    

    
    public BiGrafo(ArrayList<Node> cv1, ArrayList<Node> cv2)
    {
            v1 = cv1;
  //          posV1 = new Integer[v1.size()];
            v2 = cv2;
            iv1= new ArrayList<Node>();
            iv2= new ArrayList<Node>();
            cruces=cantidadCruces();
            actualizado=true;
    }
    
        public BiGrafo(BiGrafo b){
         v1 = new ArrayList<Node>();
    	v2 = new ArrayList<Node>();
    	
    	iv1 = new ArrayList<Node>();
    	iv2 = new ArrayList<Node>();
    	iEjes = new ArrayList<int[]>();
            this.copiar(b);
     }
    
       public void copiar(BiGrafo b){
            this.actualizado = b.actualizado;
            this.cantEjesFijo = b.cantEjesFijo;
            this.cantEjesParticionAAgregar = b.cantEjesParticionAAgregar;
            this.cantElementosOriginalV1 = b.cantElementosOriginalV1;
            this.cantElementosOriginalV2 = b.cantElementosOriginalV2;
            this.cantElementosOriginaliV1 = b.cantElementosOriginaliV1;
            this.cantElementosOriginaliV2 = b.cantElementosOriginaliV2;
            this.cruces = b.cruces;
            this.iEjes.clear();
            this.iv1.clear();
            this.iv2.clear();
            this.v1.clear();
            this.v2.clear();
            		// Agrego V1
		
            //agrego V1
            
            for(Node n : b.v1)
            {
                this.v1.add(new Node(n.v,n.fijo,n.pos));
            }
                    
              
            // Agrego V2
            for(Node n : b.v2)
            {
                this.v2.add(new Node(n.v,n.fijo,n.pos));
            }
             
                          // agrego iv1
              for(Node nodo :b.iv1)
                  this.iv1.add(new Node(nodo.v,nodo.fijo,nodo.pos));
                  // agrego iv2
              
              for(Node nodo :b.iv2)
                  this.iv2.add(new Node(nodo.v,nodo.fijo,nodo.pos));
            
  //            this.contruyeArreglosDePosiciones();
            // Agrego aristas V1 a V2	

                    Node nodo1 = null;
                    Node nodo2 = null;
                    // por cada nodo de b en V1
                     for(Node nodo: b.v1) {
                         //busco el equivalente  this en V1
                         for(dgbi.Node n :this.v1){
                             if(n.v == nodo.v){
                                 nodo1 = n;
                                 break;
                             }
                         }
                          for(Node ady:nodo.ady){	
                                if(ady.pos != -1){
                                    for(dgbi.Node n :this.v2){
                                            if(n.v == ady.v){
                                                    nodo2 = n;
                                                    break;
                                            }
                                    }
                                }
                                else{
                                   for(dgbi.Node n :this.iv2){
                                            if(n.v == ady.v){
                                                    nodo2 = n;
                                                    break;
                                            }
                                    }
                                }
                                

                                    // Agrego el Eje
                                    nodo1.ady.add(nodo2);
                                    nodo2.ady.add(nodo1);

                            }
                     }
                     

              
              
                // Agrego Aristas de IV1 a IV2
                    nodo1 = null;
                    nodo2 = null;
                     for(Node nodo: b.iv1)
                     {
                          for(dgbi.Node n :this.iv1)
                          {
                                 if(n.v == nodo.v){
                                     nodo1 = n;
                                     break;
                                 }
                          }
                            for(Node ady:nodo.ady){	
                                

                                if(ady.pos != -1)
                                {
                                  for(dgbi.Node n :this.v2){
                                            if(n.v == ady.v){
                                                    nodo2 = n;
                                                    break;
                                            }
                                    }  
                                    
                                }
                                else{
                                    for(dgbi.Node n :this.iv2){
                                            if(n.v == ady.v){
                                                    nodo2 = n;
                                                    break;
                                            }
                                    }
                                }

                                    // Agrego el Eje
                                    nodo1.ady.add(nodo2);
                                    nodo2.ady.add(nodo1);

                            }
                     }   
     }    
    
 /*
  public void contruyeArreglosDePosiciones()
    {
        posV1 = new Integer[v1.size()+iv1.size()];
        // Armo el arreglo con las posiciones de las etiquetas
        cantOpertaciones++;
        int i=0;
        cantOpertaciones++;
        int pos = 0;
        cantOpertaciones++;
        while (i<posV1.length)
        {
            cantOpertaciones++;
            if(v1.size() > i)
            {
                cantOpertaciones++;
                pos = v1.get(i).v;
                cantOpertaciones++;
                posV1[pos]=i;
            }
            cantOpertaciones++;
            i++;
            cantOpertaciones++;
        }
        cantOpertaciones++;
        posV2 = new Integer[v2.size()+iv2.size()];
        // Idem para v2
        cantOpertaciones++;
        i=0;
        cantOpertaciones++;
        while (i<posV2.length)
        {
            cantOpertaciones++;
            if(v2.size() > i)
            {
                cantOpertaciones++;
                pos = v2.get(i).v-v1.size()-iv1.size();
                cantOpertaciones++;
                posV2[pos]=i;
            }
            cantOpertaciones++;
            i++;
            cantOpertaciones++;
        }
    }
*/
    public boolean Adyacente(Node ni, Node nj)
    {
        cantOpertaciones++;
    	for(Node n : ni.ady){
            cantOpertaciones++;
    		if(nj.equals(n)) return true;
            cantOpertaciones++;
    	}
        return false;
    }
    
    public int cantidadCruces()
    {
        cantOpertaciones = 0;
        cantOpertaciones++;
   //     if (!actualizado)
    //    {
            // Armo el arreglo con las posiciones de las etiquetas
  //          contruyeArreglosDePosiciones();
            cantOpertaciones++;
            cruces=0; // Me preparo para contar..
            // Recorro todos los vértices y analizo cuales vertices de la otra particion tienen ejes que se cruzan
            cantOpertaciones++;
            int v=0;
            cantOpertaciones++;
            while (v<v1.size())
            {
                cantOpertaciones++;
                ArrayList<Node> adytsv1 = v1.get(v).ady;//g.adyacentes(V1[v].intValue()); //Obtengo los ejes adyacentes al vertice
                cantOpertaciones++;
                int nroEje=0;  // Contador para ir analizando los ejes.
                cantOpertaciones++;
                while (nroEje<adytsv1.size())
                {
                    // Recorro los ejes de todos los vertices siguientes al elegido
                    cantOpertaciones++;
                    int vertice2=v+1;
                    cantOpertaciones++;
                    while (vertice2<v1.size())
                    {
                        cantOpertaciones++;
                        ArrayList<Node> adytsv2 = v1.get(vertice2).ady;//g.adyacentes(V1[vertice2].intValue());
                        cantOpertaciones++;
                        int looper=0;
                        cantOpertaciones++;
                        Node verticeAux;
                        cantOpertaciones++;
                        while (looper<adytsv2.size())
                        {
                            cantOpertaciones++;
                            verticeAux=adytsv2.get(looper);
                            cantOpertaciones++;
                            if((verticeAux.pos != -1) && (adytsv1.get(nroEje).pos != -1))
                             {
                                cantOpertaciones++;
                                if (verticeAux.pos < adytsv1.get(nroEje).pos)
                                {
                                    cantOpertaciones++;
                                    cruces++;
                                }
                            }
                            cantOpertaciones++;
                            looper++;
                            cantOpertaciones++;
                        }
                        cantOpertaciones++;
                        vertice2++;
                        cantOpertaciones++;
                    }
                    cantOpertaciones++;
                    nroEje++;
                    cantOpertaciones++;
                }
                cantOpertaciones++;
                v++;
                cantOpertaciones++;
            }
   //     }
        cantOpertaciones++;
        actualizado=true;
        cantOpertaciones++;
        return cruces;
    }

    public int CantCortesAfterSwapV1(int PosNodoA, int PosNodoB)
    {
    	int crucesActual = cruces;
        crucesActual = crucesActual - CortesDeV1(PosNodoA);
        crucesActual = crucesActual - CortesDeV1(PosNodoB);
        SwapV1(PosNodoA,PosNodoB);
        crucesActual = crucesActual + CortesDeV1(PosNodoA);
        crucesActual = crucesActual + CortesDeV1(PosNodoB);
        SwapV1(PosNodoA,PosNodoB);
        return crucesActual; 
	}
    	
    public void ConfirmarSwapV1(int PosNodoA, int PosNodoB)
    {
    	SwapV1(PosNodoA,PosNodoB);
    	actualizado=true;
    }    
    public int CortesDeV1(int PosNodo)
    {
        
  //      contruyeArreglosDePosiciones();
        cantOpertaciones= 0;
        cantOpertaciones++;
        int crucesDe = 0;
        cantOpertaciones++;
        ArrayList<Node> adytsv1 = v1.get(PosNodo).ady;//g.adyacentes(V1[v].intValue()); //Obtengo los ejes adyacentes al vertice
        cantOpertaciones++;
        int nroEje=0;  // Contador para ir analizando los ejes.
        cantOpertaciones++;
        
        
        while (nroEje<adytsv1.size())
        {
            // Recorro los ejes de todos los vertices siguientes al elegido
            int vertice2=0;
            while (vertice2<v1.size())
            {
                if(vertice2 == PosNodo)
                {
                    vertice2++;
                    if(vertice2 ==v1.size())
                    {
                    break;
                    }
                }
                ArrayList<Node> adytsv2 = v1.get(vertice2).ady;//g.adyacentes(V1[vertice2].intValue());
                int looper=0;
                Node verticeAux;
                while (looper<adytsv2.size())
                {
                    verticeAux=adytsv2.get(looper);
                    if((verticeAux.pos != -1) && (adytsv1.get(nroEje).pos != -1))
                    {
                        if(vertice2 > PosNodo)
                        {
                        if (verticeAux.pos < adytsv1.get(nroEje).pos)
                            {
                                crucesDe++;
                            }
                        }
                        else
                        {
                            if (adytsv1.get(nroEje).pos  < verticeAux.pos)
                            {
                                crucesDe++;
                            }
                        }
                    }
                    looper++;
                }
                vertice2++;
            }
            nroEje++;
        }
        return crucesDe;
   }
        
    public int CantCortesAfterSwapV2(int PosNodoA, int PosNodoB)
    {
    	int crucesActual = cruces;
        crucesActual = crucesActual - CortesDeV2(PosNodoA);
        crucesActual = crucesActual - CortesDeV2(PosNodoB);
        SwapV1(PosNodoA,PosNodoB);
        crucesActual = crucesActual + CortesDeV2(PosNodoA);
        crucesActual = crucesActual + CortesDeV2(PosNodoB);
        SwapV1(PosNodoA,PosNodoB);
        return crucesActual; 
    }
    	
    public void ConfirmarSwapV2(int PosNodoA, int PosNodoB)
    {
    	SwapV2(PosNodoA,PosNodoB);
    	actualizado=true;
    }
    
    public int CortesDeV2(int PosNodo)
    {
  //      contruyeArreglosDePosiciones();
        cantOpertaciones = 0;
        cantOpertaciones++;
        int crucesDe = 0;
        cantOpertaciones++;
        ArrayList<Node> adytsv2 = v2.get(PosNodo).ady;//g.adyacentes(V1[v].intValue()); //Obtengo los ejes adyacentes al vertice
        cantOpertaciones++;
        int nroEje=0;  // Contador para ir analizando los ejes.
        cantOpertaciones++;
        while (nroEje<adytsv2.size())
        {
            cantOpertaciones++;
            // Recorro los ejes de todos los vertices siguientes al elegido
            int vertice2=0;
            cantOpertaciones++;
            while (vertice2<v2.size())
            {
                cantOpertaciones++;
                if(vertice2 == PosNodo)
                {
                    cantOpertaciones++;
                    vertice2++;
                    cantOpertaciones++;
                    if(vertice2 ==v2.size())
                    {
                    break;
                    }
                }
                cantOpertaciones++;
                ArrayList<Node> adytsv1 = v2.get(vertice2).ady;//g.adyacentes(V1[vertice2].intValue());
                cantOpertaciones++;
                int looper=0;
                cantOpertaciones++;
                Node verticeAux;
                cantOpertaciones++;
                while (looper<adytsv1.size())
                {
                    cantOpertaciones++;
                    verticeAux=adytsv1.get(looper);
                    cantOpertaciones++;
                    if((verticeAux.pos != -1) && (adytsv2.get(nroEje).pos != -1))
                    {
                        cantOpertaciones++;
                        if(vertice2 > PosNodo)
                        {
                        if (verticeAux.pos < adytsv2.get(nroEje).pos)
                        {
                            cantOpertaciones++;
                            crucesDe++;
                        }
                        }
                        else
                        {
                            if (adytsv2.get(nroEje).pos < verticeAux.pos)
                            {
                                cantOpertaciones++;
                                crucesDe++;
                            }
                        }
                    }
                    cantOpertaciones++;
                    looper++;
                    cantOpertaciones++;
                }
                cantOpertaciones++;
                vertice2++;
                cantOpertaciones++;
            }
            cantOpertaciones++;
            nroEje++;
            cantOpertaciones++;
        }
        cantOpertaciones++;
        return crucesDe;
    }
    	
	
    public void SwapV1(int a, int b)
    {
    	Integer aAfterSwap = v1.get(a).v;
    	v1.get(a).v = v1.get(b).v;
    	v1.get(b).v = aAfterSwap;
    }

    public void SwapV2(int a, int b)
    {
    	Integer aAfterSwap = v2.get(a).v;
    	v2.get(a).v = v2.get(b).v;
    	v2.get(b).v = aAfterSwap;
    }    
   
      public void mainBi() {
    	  	//BiGrafo big = new BiGrafo();
    	  	/* Grafo ejemplo:
    	  	 *   
    	  	 *   v1  v2
    	  	 *   
    	  	 * 	 0   1
    	  	 *        \ /
    	  	 *         X	
    	  	 *	  / \  
    	  	 *       2   3
      		 */
    /*	  	
    	  	Node n1 = new Node(0,false);
    	  	Node n2 = new Node(1,false);
    	  	Node n3 = new Node(2,false);
    	  	Node n4 = new Node(3,false);
    	  	 
    	  	 // agrego las adyacencias
    	  	 n1.ady.add(n4);
    	  	 n2.ady.add(n3);
    	   	 n3.ady.add(n2);
    	   	 n4.ady.add(n1);
    	  	 
    	  	 // agrego los nodos a los conjuntos
    	  	 v1.add(n2);
    	  	 v1.add(n1);
    	  	 v2.add(n4);
    	  	 v2.add(n3);
      //          contruyeArreglosDePosiciones();                 
                cruces=cantidadCruces();
                actualizado=true;                 
     * */
      }
  
}




